﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Brettle.Web.NeatUpload;
using mojoPortal.Business;
using mojoPortal.Business.WebHelpers;
using mojoPortal.Net;
using mojoPortal.Web.Editor;
using mojoPortal.Web.Framework;
using mojoPortal.Web;
using Resources;
using log4net;
using ud_Article.Business;
using ud_Utilities;
using System.Drawing;
using Image = System.Web.UI.WebControls.Image;

namespace ud_Article.UI
{
    public partial class BlogEdit : mojoBasePage
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(BlogEdit));

        protected int moduleId = -1;
        protected int itemId = -1;
        protected int pageId = -1;

        private int loadedModuleId = -1;
        private int loadedPageId = -1;
        private int loadedSiteId = -1;
        private SiteSettings settingsSync;
        protected String cacheDependencyKey;
        protected string virtualRoot;
        protected Double timeOffset;
        private TimeZoneInfo timeZone;
        protected Hashtable moduleSettings;
        protected ArticleConfiguration config = new ArticleConfiguration();
        private int pageNumber = 1;
        private const int pageSize = 10;
        private int totalPages = 1;
        private Guid restoreGuid = Guid.Empty;
        private Article article;
        private Article articleSync;
        private bool enableContentVersioning;
        protected bool isAdmin;
        readonly ContentMetaRespository metaRepository = new ContentMetaRespository();
        private int catId = -1;
        readonly DBArticleCategory repositoryCategory = new DBArticleCategory();
        ud_ArticleCategory itemCategory = new ud_ArticleCategory();
        readonly SiteUser siteUser = SiteUtils.GetCurrentSiteUser();
        private bool isUserPost;
        private bool isPublisher;

        #region OnInit

        protected override void OnPreInit(EventArgs e)
        {
            AllowSkinOverride = true;
            base.OnPreInit(e);
        }

        override protected void OnInit(EventArgs e)
        {
            LoadParams();
            LoadSettings();
            LoadPanels();
            base.OnInit(e);
            Load += Page_Load;

            //ScriptConfig.IncludeYuiTabs = true;
            //IncludeYuiTabsCss = true;
            rptAttachments.ItemDataBound += rptAttachments_ItemDataBound;
            rptAttachments.ItemCommand += rptAttachments_ItemCommand;
            btnUpload.Click += btnUpload_Click;

            btnUpdate.Click += btnUpdate_Click;
            btnUpdate2.Click += btnUpdate_Click;
            btnUpdate3.Click += btnUpdate_Click;
            btnUpdate4.Click += btnUpdate_Click;
            btnDelete.Click += btnDelete_Click;
            btnDelete2.Click += btnDelete_Click;
            btnDelete3.Click += btnDelete_Click;
            btnDelete4.Click += btnDelete_Click;

            btnDeleteImg.Click += btnDeleteImg_Click;

            btnSaveAndPreview.Click += btnSaveAndPreview_Click;

            grdHistory.RowCommand += grdHistory_RowCommand;
            grdHistory.RowDataBound += grdHistory_RowDataBound;
            pgrHistory.Command += pgrHistory_Command;
            btnRestoreFromGreyBox.Click += btnRestoreFromGreyBox_Click;
            btnDeleteHistory.Click += btnDeleteHistory_Click;

            grdContentMeta.RowCommand += grdContentMeta_RowCommand;
            grdContentMeta.RowEditing += grdContentMeta_RowEditing;
            grdContentMeta.RowUpdating += grdContentMeta_RowUpdating;
            grdContentMeta.RowCancelingEdit += grdContentMeta_RowCancelingEdit;
            grdContentMeta.RowDeleting += grdContentMeta_RowDeleting;
            grdContentMeta.RowDataBound += grdContentMeta_RowDataBound;
            btnAddMeta.Click += btnAddMeta_Click;

            grdMetaLinks.RowCommand += grdMetaLinks_RowCommand;
            grdMetaLinks.RowEditing += grdMetaLinks_RowEditing;
            grdMetaLinks.RowUpdating += grdMetaLinks_RowUpdating;
            grdMetaLinks.RowCancelingEdit += grdMetaLinks_RowCancelingEdit;
            grdMetaLinks.RowDeleting += grdMetaLinks_RowDeleting;
            grdMetaLinks.RowDataBound += grdMetaLinks_RowDataBound;
            btnAddMetaLink.Click += btnAddMetaLink_Click;

            SiteUtils.SetupEditor(edContent);
            SiteUtils.SetupEditor(edExcerpt);
        }


        #endregion

        private void Page_Load(object sender, EventArgs e)
        {
            Page.EnableViewState = true;
            if (!Request.IsAuthenticated)
            {
                SiteUtils.RedirectToLoginPage(this);
                return;
            }

            SecurityHelper.DisableBrowserCache();

            if (!UserCanEditModule(moduleId) && !isUserPost && !isPublisher)
            {
                SiteUtils.RedirectToEditAccessDeniedPage();
                return;
            }
            PopulateLabels();
            SetupScripts();
            if ((Request.UrlReferrer != null) && (hdnReturnUrl.Value.Length == 0))
            {
                hdnReturnUrl.Value = Request.UrlReferrer.ToString();
                lnkCancel.NavigateUrl = Request.UrlReferrer.ToString();
                lnkCancel2.NavigateUrl = lnkCancel.NavigateUrl;
                lnkCancel3.NavigateUrl = lnkCancel.NavigateUrl;
                lnkCancel4.NavigateUrl = lnkCancel.NavigateUrl;

            }
            else
            {
                lnkCancel.Visible = false;
                lnkCancel2.Visible = false;
                lnkCancel3.Visible = false;
                lnkCancel4.Visible = false;
            }
            if (!Page.IsPostBack)
            {
                PopulateControls();
                PopulateCategories();
                PopulateCategoriesSyncPost();
                BindMeta();
                BindMetaLinks();
            }
        }

        protected virtual void PopulateControls()
        {
            if (article != null)
            {
                dpBeginDate.ShowTime = true;
                dpBeginDate.Text = timeZone != null ? article.StartDate.ToLocalTime(timeZone).ToString("g") : DateTimeHelper.LocalizeToCalendar(article.StartDate.AddHours(timeOffset).ToString("g"));
                txtTitle.Text = article.Title;
                txtItemUrl.Text = article.ItemUrl;
                txtLocation.Text = article.Location;
                edContent.Text = article.Description;
                edExcerpt.Text = article.Excerpt;
                txtTag.Text = article.Tag;
                txtOverrideUrl.Text = article.OverrideUrl;
                txtMetaDescription.Text = article.MetaDescription;

                if (!string.IsNullOrEmpty(article.ImageUrl))
                {
                    divImage.Visible = true;
                    imgView.ImageUrl = "~/" + ConfigurationManager.AppSettings["ArticleImagesFolder"] + article.ImageUrl;
                }
                else { divImage.Visible = false; }
                if(article.SyncItemID > 0)
                {
                    chkSyncPost.Checked = true;
                }
                txtMetaKeywords.Text = article.MetaKeywords;
                chkIncludeInFeed.Checked = article.IncludeInFeed;
                chkIsPublished.Checked = article.IsPublished;
                ListItem item
                    = ddCommentAllowedForDays.Items.FindByValue(article.AllowCommentsForDays.ToInvariantString());
                if (item != null)
                {
                    ddCommentAllowedForDays.ClearSelection();
                    item.Selected = true;
                }

                if (restoreGuid != Guid.Empty)
                {
                    ContentHistory rHistory = new ContentHistory(restoreGuid);
                    if (rHistory.ContentGuid == article.BlogGuid)
                    {
                        edContent.Text = rHistory.ContentText;
                    }

                }
                // show preview button for saved drafts
                if ((!article.IsPublished) || (article.StartDate > DateTime.UtcNow)) { btnSaveAndPreview.Visible = true; }

                BindHistory();
                BindAttachments();
            }
            else
            {
                chkIncludeInFeed.Checked = true;
                dpBeginDate.Text = DateTimeHelper.LocalizeToCalendar(DateTime.UtcNow.AddHours(timeOffset).ToString("g"));
                btnDelete.Visible = false;
                pnlHistory.Visible = false;
            }

            if ((txtItemUrl.Text.Length == 0) && (txtTitle.Text.Length > 0))
            {
                string friendlyUrl = WebConfigSettings.AppendDateToBlogUrls
                                         ? SiteUtils.SuggestFriendlyUrl(
                                             txtTitle.Text + "-" +
                                             DateTime.UtcNow.AddHours(timeOffset).ToString("yyyy-MM-dd"), siteSettings)
                                         : SiteUtils.SuggestFriendlyUrl(txtTitle.Text, siteSettings);

                txtItemUrl.Text = @"~/" + friendlyUrl;
            }

            if (article != null)
            {
                hdnTitle.Value = txtTitle.Text;
            }

        }


        void rptAttachments_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            if (e.CommandName != "DeleteItem") return;
            DBArticleAttachment repository = new DBArticleAttachment();
            bool a = repository.DeleteItemAttachment(e.CommandArgument.ToString());
            bool b = repository.Delete(e.CommandArgument.ToString());
            if (a && b)
            {
                string path = Request.PhysicalApplicationPath + "Data/ArticleAttachments/" + e.CommandArgument;
                path = path.Replace("/", "\\");
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
            }
            WebUtils.SetupRedirect(this, Request.RawUrl);
        }

        void rptAttachments_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            Image imgType = (Image)e.Item.FindControl("imgType");
            if (imgType == null) return;
            string name = DataBinder.Eval(e.Item.DataItem, "q.FileName", "{0}").Trim();
            // ReSharper disable PossibleNullReferenceException
            string imgFile = Path.GetExtension(name).ToLower().Replace(".", "") + ".png";
            string path = Request.PhysicalApplicationPath + "/Data/SiteImages/Icons/" + imgFile;
            if (File.Exists(path))
            {
                imgType.ImageUrl = ImageSiteRoot + "/Data/SiteImages/Icons/" + imgFile;
            }
            ImageButton ibtnDelete = (ImageButton)e.Item.FindControl("ibtnDelete");
            Utilities.AddConfirmButton(ibtnDelete, ArticleResources.DeleteConfirmation);
            // ReSharper restore PossibleNullReferenceException
        }

        void btnUpload_Click(object sender, EventArgs e)
        {
            string upLoadPath = Page.Server.MapPath(WebUtils.GetApplicationRoot() + "/Data/ArticleAttachments/");
            if (!Directory.Exists(upLoadPath))
            {
                Directory.CreateDirectory(upLoadPath);
            }
            if (itemId == -1 || article == null || article.ItemId <= 0)
            {
                Page.Validate("blog");
                if ((!Page.IsValid) || (!ParamsAreValid())) return;
                Save();
            }
            if (article == null) { WebUtils.SetupRedirect(this, Request.RawUrl); return; }
            if ((article.ItemId <= 0) || (article.ModuleId != moduleId)) { WebUtils.SetupRedirect(this, Request.RawUrl); return; }
            if (file1.HasFile && file1.FileName != null && file1.FileName.Trim().Length > 0)
            {
                DBArticleAttachment repository = new DBArticleAttachment();
                string serverFileName = Guid.NewGuid() + ".config";
                int fileID;
                repository.Create(moduleId, file1.FileName, serverFileName, (int)(file1.ContentLength / 1024), out fileID);
                if (article.SyncItemID > 0 && articleSync != null && articleSync.ItemId > 0)
                {
                    int fileIDSync;
                    repository.Create(articleSync.ModuleId, file1.FileName, serverFileName,
                                      (int) (file1.ContentLength/1024),
                                      out fileIDSync);
                    if (fileIDSync <= 0)
                    {
                        return;
                    }
                    repository.CreateItemAttachment(articleSync.ModuleId, articleSync.ItemId, fileIDSync);
                }
                if (fileID <= 0)
                {
                    return;
                }
                if (repository.CreateItemAttachment(moduleId, article.ItemId, fileID))
                {
                    
                    string destPath = upLoadPath + serverFileName;
                    if (File.Exists(destPath))
                    {
                        File.Delete(destPath);
                    }
                    file1.MoveTo(destPath, MoveToOptions.Overwrite);
                }
            }
            CurrentPage.UpdateLastModifiedTime();
            CacheHelper.TouchCacheDependencyFile(cacheDependencyKey);
            WebUtils.SetupRedirect(this, SiteRoot + article.ItemUrl.Replace("~/", "/"));
        }

        void btnDeleteImg_Click(object sender, ImageClickEventArgs e)
        {
            if (article == null) { article = new Article(itemId); }

            DeleteImageFromServer();
            divImage.Visible = false;
            article.ImageUrl = string.Empty;
            article.Save();
            if (articleSync == null) return;
            articleSync.ImageUrl = string.Empty;
            articleSync.Save();
        }

        private void BindAttachments()
        {
            DBArticleAttachment repository = new DBArticleAttachment();
            rptAttachments.DataSource = repository.GetByItemID(itemId);
            rptAttachments.DataBind();
            lblAttachments.Visible = rptAttachments.Items.Count > 0;
        }

        private void PopulateCategoriesSyncPost()
        {
            if (lbCategoriesSyncPost == null)
            {
                log.Error("lbCategoriesSyncPost was null");
                lbCategoriesSyncPost = (ListBox)UpdatePanel2.FindControl("lbCategoriesSyncPost");
            }
            List<ud_ArticleCategory> roots = repositoryCategory.GetRoot(loadedModuleId);
            foreach (ud_ArticleCategory item in roots)
            {
                ListItem list = new ListItem
                {
                    Text = item.Category + @" (" + item.SortOrder + @")",
                    Value = item.CategoryID.ToString()
                };
                lbCategoriesSyncPost.Items.Add(list);
            }
            //lbCategoriesSyncPost.Items.Remove(lbCategoriesSyncPost.Items.FindByValue(catId.ToString()));
            PopulateChildNode(lbCategoriesSyncPost);
            lbCategoriesSyncPost.Items.Insert(0, new ListItem(ArticleResources.NoCategory, "0"));
            lbCategoriesSyncPost.Items[0].Selected = true;
            if (articleSync == null) return;
            ud_ArticleCategory categorySync = repositoryCategory.GetOneByArticleID(articleSync.ItemId);
            if (categorySync.CategoryID > 0 && lbCategoriesSyncPost.Items.FindByValue(categorySync.CategoryID.ToString()) != null)
            {
                lbCategoriesSyncPost.Items[0].Selected = false;
                lbCategoriesSyncPost.Items.FindByValue(categorySync.CategoryID.ToString()).Selected = true;
            }
        }


        private void PopulateCategories()
        {
            if (lbCategories == null)
            {
                log.Error("lbCategories was null");
                lbCategories = (ListBox)UpdatePanel1.FindControl("lbCategories");
            }
            List<ud_ArticleCategory> roots = repositoryCategory.GetRoot(moduleId);
            foreach (ud_ArticleCategory item in roots)
            {
                ListItem list = new ListItem
                {
                    Text = item.Category + @" (" + item.SortOrder + @")",
                    Value = item.CategoryID.ToString()
                };
                lbCategories.Items.Add(list);
            }
            //lbCategories.Items.Remove(lbCategories.Items.FindByValue(catId.ToString()));
            PopulateChildNode(lbCategories);
            lbCategories.Items.Insert(0, new ListItem(ArticleResources.NoCategory, "0"));
            if (catId > 0)
            {
                lbCategories.Items.FindByValue(catId.ToString()).Selected = true;
            }
            else
            {
                lbCategories.Items[0].Selected = true;
            }
            catId = WebUtils.ParseInt32FromQueryString("catid", -1);
            if (catId > 0)
            {
                lbCategories.Enabled = false;
            }
        }

        private void PopulateChildNode(ListControl root)
        {
            for (int i = 0; i < root.Items.Count; i++)
            {
                List<ud_ArticleCategory> children = repositoryCategory.GetChildren(int.Parse(root.Items[i].Value));
                if (children.Count <= 0) continue;
                string prefix = string.Empty;
                while (root.Items[i].Text.StartsWith("|"))
                {
                    prefix += root.Items[i].Text.Substring(0, 3);
                    root.Items[i].Text = root.Items[i].Text.Remove(0, 3);
                }
                root.Items[i].Text = prefix + root.Items[i].Text;
                int index = 1;
                foreach (ud_ArticleCategory child in children)
                {
                    //if (child.CategoryID.Equals(catId)) continue;
                    ListItem list = new ListItem
                    {
                        Text = prefix + @"|--" + child.Category + @" (" + child.SortOrder + @")",
                        Value = child.CategoryID.ToString()
                    };
                    root.Items.Insert(root.Items.IndexOf(root.Items[i]) + index, list);
                    index++;
                }
            }
        }
        
        protected virtual void btnUpdate_Click(object sender, EventArgs e)
        {
            Page.Validate("blog");
            if (!Page.IsValid) return;
            if (!Save()) return;
            string url = SiteRoot + "/Article/EditPost.aspx?pageid=" + pageId + "&mid=" + moduleId + "&ItemID=" +
                         article.ItemId;
            if (itemId > -1 || !config.UseAttachmentSetting)
            {
                //if (hdnReturnUrl.Value.Length > 0 && hdnReturnUrl.Value != url)
                //{
                //    WebUtils.SetupRedirect(this, hdnReturnUrl.Value);
                //    return;
                //}
                //WebUtils.SetupRedirect(this, SiteUtils.GetCurrentPageUrl());
                WebUtils.SetupRedirect(this, SiteRoot + article.ItemUrl.Replace("~/", "/"));
            }
            else
            {
                WebUtils.SetupRedirect(this, url);    
            }
        }

        void btnSaveAndPreview_Click(object sender, EventArgs e)
        {
            Page.Validate("blog");
            if ((!Page.IsValid) || (!ParamsAreValid())) return;
            if (!Save()) return;
            btnUpload_Click(null, null);
            WebUtils.SetupRedirect(this, SiteRoot + article.ItemUrl.Replace("~/", "/"));
        }

        private bool ParamsAreValid()
        {
            try
            {
                DateTime.Parse(dpBeginDate.Text);
            }
            catch (FormatException)
            {
                lblErrorMessage.Text = ArticleResources.ParseDateFailureMessage;
                return false;
            }
            catch (ArgumentNullException)
            {
                lblErrorMessage.Text = ArticleResources.ParseDateFailureMessage;
                return false;
            }
            return true;
        }

        private string SuggestUrl()
        {
            string pageName = txtTitle.Text;
            if (WebConfigSettings.AppendDateToBlogUrls)
            {
                if (timeZone != null)
                {
                    pageName += "-" + DateTime.UtcNow.ToLocalTime(timeZone).ToString("yyyy-MM-dd");
                }
                else
                {
                    pageName += "-" + DateTime.UtcNow.AddHours(timeOffset).ToString("yyyy-MM-dd");
                }

            }
            return SiteUtils.SuggestFriendlyUrl(pageName, siteSettings);
        }

        private bool Save()
        {
            if (article == null) { article = new Article(itemId); }
            Module module = GetModule(moduleId);
            if (module == null) { return false; }
            
            if (siteUser == null) { return false; }
            article.UserGuid = siteUser.UserGuid;
            article.LastModUserGuid = siteUser.UserGuid;
            article.ContentChanged += blog_ContentChanged;

            article.ModuleId = moduleId;
            article.ModuleGuid = module.ModuleGuid;
            DateTime localTime = DateTime.Parse(dpBeginDate.Text, CultureInfo.CurrentCulture);
            article.StartDate = timeZone != null ? localTime.ToUtc(timeZone) : localTime.AddHours(-timeOffset);
            article.Title = txtTitle.Text;
            article.Location = txtLocation.Text;
            article.Description = edContent.Text;
            article.Excerpt = edExcerpt.Text;
            article.UserName = Context.User.Identity.Name;
            article.IncludeInFeed = chkIncludeInFeed.Checked;
            article.IsPublished = chkIsPublished.Checked;
            article.Tag = txtTag.Text;
            article.OverrideUrl = txtOverrideUrl.Text;
// ReSharper disable RedundantAssignment
            int allowComentsForDays = -1;
// ReSharper restore RedundantAssignment
            int.TryParse(ddCommentAllowedForDays.SelectedValue, out allowComentsForDays);
            article.AllowCommentsForDays = allowComentsForDays;
            article.MetaDescription = txtMetaDescription.Text;
            article.MetaKeywords = txtMetaKeywords.Text;
            
            if (txtItemUrl.Text.Length == 0)
            {
                txtItemUrl.Text = SuggestUrl();
            }

            String friendlyUrlString = SiteUtils.RemoveInvalidUrlChars(txtItemUrl.Text.Replace("~/", String.Empty));
            FriendlyUrl friendlyUrl = new FriendlyUrl(siteSettings.SiteId, friendlyUrlString);

            if (
                ((friendlyUrl.FoundFriendlyUrl) && (friendlyUrl.PageGuid != article.BlogGuid))
                && (article.ItemUrl != txtItemUrl.Text)
                )
            {
                lblError.Text = ArticleResources.PageUrlInUseBlogErrorMessage;
                return false;
            }

            if (!friendlyUrl.FoundFriendlyUrl)
            {
                if (WebPageInfo.IsPhysicalWebPage("~/" + friendlyUrlString))
                {
                    lblError.Text = ArticleResources.PageUrlInUseBlogErrorMessage;
                    return false;
                }
            }

            string oldUrl = article.ItemUrl.Replace("~/", string.Empty);
            string newUrl = SiteUtils.RemoveInvalidUrlChars(txtItemUrl.Text.Replace("~/", string.Empty));

            article.ItemUrl = "~/" + newUrl;

            string fileName;
            if (!SaveImageUrl(out fileName))
            {
                return false;
            }
            if (!fileName.Equals(string.Empty))
            {
                article.ImageUrl = fileName;
            }

            if (enableContentVersioning)
            {
                article.CreateHistory(siteSettings.SiteGuid);
            }
            article.IsHot = chkIsHot.Checked;
            article.IsRandomize = chkIsRandomize.Checked;
            article.Save();

            if (!friendlyUrl.FoundFriendlyUrl)
            {
                if ((friendlyUrlString.Length > 0) && (!WebPageInfo.IsPhysicalWebPage("~/" + friendlyUrlString)))
                {
                    FriendlyUrl newFriendlyUrl = new FriendlyUrl
                                                     {
                                                         SiteId = siteSettings.SiteId,
                                                         SiteGuid = siteSettings.SiteGuid,
                                                         PageGuid = article.BlogGuid,
                                                         Url = friendlyUrlString,
                                                         RealUrl = "~/Article/ViewPost.aspx?pageid="
                                                                   + pageId.ToInvariantString()
                                                                   + "&mid=" + article.ModuleId.ToInvariantString()
                                                                   + "&ItemID=" + article.ItemId.ToInvariantString()
                                                     };

                    newFriendlyUrl.Save();
                }

                //if post was renamed url will change, if url changes we need to redirect from the old url to the new with 301
                if ((oldUrl.Length > 0) && (newUrl.Length > 0) && (!SiteUtils.UrlsMatch(oldUrl, newUrl)))
                {
                    //worry about the risk of a redirect loop if the page is restored to the old url again
                    // don't create it if a redirect for the new url exists
                    if (
                        (!RedirectInfo.Exists(siteSettings.SiteId, oldUrl))
                        && (!RedirectInfo.Exists(siteSettings.SiteId, newUrl))
                        )
                    {
                        RedirectInfo redirect = new RedirectInfo
                                                    {
                                                        SiteGuid = siteSettings.SiteGuid,
                                                        SiteId = siteSettings.SiteId,
                                                        OldUrl = oldUrl,
                                                        NewUrl = newUrl
                                                    };
                        redirect.Save();
                    }
                    // since we have created a redirect we don't need the old friendly url
                    FriendlyUrl oldFriendlyUrl = new FriendlyUrl(siteSettings.SiteId, oldUrl);
                    if ((oldFriendlyUrl.FoundFriendlyUrl) && (oldFriendlyUrl.PageGuid == article.BlogGuid))
                    {
                        FriendlyUrl.DeleteUrl(oldFriendlyUrl.UrlId);
                    }

                }
            }

            // new item posted so ping services
            if ((itemId == -1) && (article.IsPublished) && (article.StartDate <= DateTime.UtcNow))
            {
                QueuePings();
            }

            CurrentPage.UpdateLastModifiedTime();

            String blogFriendlyUrl = "blog" + article.ModuleId.ToInvariantString() + "rss.aspx";
            if (!FriendlyUrl.Exists(siteSettings.SiteId, blogFriendlyUrl))
            {
                FriendlyUrl rssUrl = new FriendlyUrl
                                         {
                                             SiteId = siteSettings.SiteId,
                                             SiteGuid = siteSettings.SiteGuid,
                                             PageGuid = article.ModuleGuid,
                                             Url = blogFriendlyUrl,
                                             RealUrl = "~/Article/RSS.aspx?pageid=" + pageId.ToInvariantString()
                                                       + "&mid=" + article.ModuleId.ToInvariantString()
                                         };
                rssUrl.Save();
            }
            
            Article.DeleteItemCategories(article.ItemId);

            // Mono doesn't see this in update panel
            // so help find it
            if (lbCategories == null)
            {
                log.Error("lbCategories was null");

                lbCategories = (ListBox)UpdatePanel1.FindControl("lbCategories");
            }
            Int32 categoryId;
            Int32.TryParse(lbCategories.SelectedValue, out categoryId);
            if (categoryId > 0)
            {
                Article.AddItemCategory(article.ItemId, categoryId);
            }
            SaveSyncPost();
            CacheHelper.TouchCacheDependencyFile(cacheDependencyKey);
            SiteUtils.QueueIndexing();
            EmailNewPost();
            return true;
        }

        private void SaveSyncPost()
        {
            if (!chkSyncPost.Checked)
            {
                if (articleSync != null)
                {
                    articleSync.ContentChanged += blog_ContentChanged;
                    articleSync.DeleteSync();
                    FriendlyUrl.DeleteByPageGuid(articleSync.BlogGuid);
                    article.SyncItemID = 0;
                    article.Save();
                }
                return;
            }
            if (loadedModuleId < 0 ) return;
            if (loadedSiteId < 1) return;
            if(articleSync == null)
            {
                articleSync = new Article();
            }
            Module moduleSync = new Module(loadedModuleId);
            articleSync.AllowCommentsForDays = article.AllowCommentsForDays;
            articleSync.CompiledMeta = article.CompiledMeta;
            articleSync.CreatedUtc = article.CreatedUtc;
            articleSync.Description = article.Description;
            articleSync.Excerpt = article.Excerpt;
            articleSync.HitCount = article.HitCount;
            articleSync.ImageUrl = article.ImageUrl;
            articleSync.IsHot = article.IsHot;
            articleSync.IsRandomize = article.IsRandomize;
            articleSync.IsPublished = chkIsPublishedSyncPost.Checked;
            articleSync.IsInNewsletter = article.IsInNewsletter;
            articleSync.IncludeInFeed = article.IncludeInFeed;
            articleSync.LastModUserGuid = article.LastModUserGuid;
            articleSync.LastModUtc = article.LastModUtc;
            articleSync.Location = article.Location;
            articleSync.MetaDescription = article.MetaDescription;
            articleSync.MetaKeywords = article.MetaKeywords;
            articleSync.ModuleGuid = moduleSync.ModuleGuid;
            articleSync.ModuleId = moduleSync.ModuleId;
            articleSync.StartDate = article.StartDate;
            articleSync.Title = article.Title;
            articleSync.UserGuid = article.UserGuid;
            articleSync.UserName = article.UserName;
            articleSync.SyncItemID = article.ItemId;
            articleSync.Tag = article.Tag;
            articleSync.OverrideUrl = article.OverrideUrl;
            articleSync.Save();
            article.SyncItemID = articleSync.ItemId;
            article.Save();
            String friendlyUrlString = SiteUtils.RemoveInvalidUrlChars(txtItemUrl.Text.Replace("~/", String.Empty));
            FriendlyUrl friendlyUrl = new FriendlyUrl(settingsSync.SiteId, friendlyUrlString);

            if (((friendlyUrl.FoundFriendlyUrl) && (friendlyUrl.PageGuid != articleSync.BlogGuid))
                && (articleSync.ItemUrl != txtItemUrl.Text)
                )
            {
                lblError.Text = ArticleResources.PageUrlInUseBlogErrorMessage;
                return;
            }

            if (!friendlyUrl.FoundFriendlyUrl)
            {
                if (WebPageInfo.IsPhysicalWebPage("~/" + friendlyUrlString))
                {
                    lblError.Text = ArticleResources.PageUrlInUseBlogErrorMessage;
                    return;
                }
            }

            string oldUrl = articleSync.ItemUrl.Replace("~/", string.Empty);
            string newUrl = SiteUtils.RemoveInvalidUrlChars(txtItemUrl.Text.Replace("~/", string.Empty));

            articleSync.ItemUrl = "~/" + newUrl;
            articleSync.Save();
            
            if (!friendlyUrl.FoundFriendlyUrl)
            {
                if ((friendlyUrlString.Length > 0) && (!WebPageInfo.IsPhysicalWebPage("~/" + friendlyUrlString)))
                {
                    FriendlyUrl newFriendlyUrl = new FriendlyUrl
                    {
                        SiteId = settingsSync.SiteId,
                        SiteGuid = settingsSync.SiteGuid,
                        PageGuid = articleSync.BlogGuid,
                        Url = friendlyUrlString,
                        RealUrl = "~/Article/ViewPost.aspx?pageid="
                                  + loadedPageId.ToInvariantString()
                                  + "&mid=" + articleSync.ModuleId.ToInvariantString()
                                  + "&ItemID=" + articleSync.ItemId.ToInvariantString()
                    };

                    newFriendlyUrl.Save();
                }

                //if post was renamed url will change, if url changes we need to redirect from the old url to the new with 301
                if ((oldUrl.Length > 0) && (newUrl.Length > 0) && (!SiteUtils.UrlsMatch(oldUrl, newUrl)))
                {
                    //worry about the risk of a redirect loop if the page is restored to the old url again
                    // don't create it if a redirect for the new url exists
                    if (
                        (!RedirectInfo.Exists(settingsSync.SiteId, oldUrl))
                        && (!RedirectInfo.Exists(settingsSync.SiteId, newUrl))
                        )
                    {
                        RedirectInfo redirect = new RedirectInfo
                        {
                            SiteGuid = settingsSync.SiteGuid,
                            SiteId = settingsSync.SiteId,
                            OldUrl = oldUrl,
                            NewUrl = newUrl
                        };
                        redirect.Save();
                    }
                    // since we have created a redirect we don't need the old friendly url
                    FriendlyUrl oldFriendlyUrl = new FriendlyUrl(settingsSync.SiteId, oldUrl);
                    if ((oldFriendlyUrl.FoundFriendlyUrl) && (oldFriendlyUrl.PageGuid == articleSync.BlogGuid))
                    {
                        FriendlyUrl.DeleteUrl(oldFriendlyUrl.UrlId);
                    }

                }
            }
            Article.DeleteItemCategories(articleSync.ItemId);
            // Mono doesn't see this in update panel
            // so help find it
            if (lbCategoriesSyncPost == null)
            {
                log.Error("lbCategoriesSyncPost was null");

                lbCategoriesSyncPost = (ListBox)UpdatePanel1.FindControl("lbCategoriesSyncPost");
            }
            Int32 categoryId;
            Int32.TryParse(lbCategoriesSyncPost.SelectedValue, out categoryId);
            if (categoryId > 0)
            {
                Article.AddItemCategory(articleSync.ItemId, categoryId);
            }
        }

        private void EmailNewPost()
        {
            if (config.EmailNewPost == null || config.EmailNewPost.Count == 0) return;
            SmtpSettings smtpSettings = SiteUtils.GetSmtpSettings();
            string fromAddress = siteSettings.DefaultEmailFromAddress;
            StringBuilder message = new StringBuilder();
            if (article != null)
            {
                if (articleSync != null)
                {
                    message.Append(String.Format(ArticleResources.SubjectEmailNewPostBody, siteUser.Name,
                                                 settingsSync.SiteName, "<a href=" +
                                                 Page.ResolveUrl(ImageSiteRoot + settingsSync.SiteFolderName +
                                                                 articleSync.ItemUrl.Replace("~", string.Empty)) + ">" + articleSync.Title + "</a>",
                                                 "<a href=" +
                                                 Page.ResolveUrl(ImageSiteRoot + settingsSync.SiteFolderName + "/Article/EditPost.aspx?pageid=" + loadedPageId + "&mid=" + articleSync.ModuleId + "&itemid=" + articleSync.ItemId) + ">",
                                                 "</a>", "<p>", "</p>"));
                }
                else
                {
                    message.Append(String.Format(ArticleResources.SubjectEmailNewPostBodyNoSync, siteUser.Name,
                                                 siteSettings.SiteName,
                                                 "<a href=" +
                                                 Page.ResolveUrl(SiteRoot + article.ItemUrl.Replace("~", string.Empty)) +
                                                 ">" + article.Title + "</a>", "<p>", "</p>"));
                }
            }
            string subject = ArticleResources.SubjectEmailNewPost;
            if (article != null)
            {
                subject = article.Title;
            }
            foreach (string to in config.EmailNewPost)
            {
                EmailMessageTask messageTask = new EmailMessageTask(smtpSettings)
                {
                    EmailFrom = fromAddress,
                    EmailBcc = string.Empty,
                    EmailTo = to,
                    Subject = subject,
                    TextBody = message.ToString(),
                    SiteGuid = siteSettings.SiteGuid,
                    PreferredEncoding = "utf-8"
                };
                messageTask.QueueTask();
                WebTaskManager.StartOrResumeTasks();
            }
        }

        private bool SaveImageUrl(out string fileName)
        {
            String pathToApplicationsFolder
                = HttpContext.Current.Server.MapPath(
                "~/" + ConfigurationManager.AppSettings["ArticleImagesFolder"]);
            if (!Directory.Exists(pathToApplicationsFolder))
            {
                Directory.CreateDirectory(pathToApplicationsFolder);
            }
            bool flag = false;
            int width = 0;
            int height = 0;
            fileName = string.Empty;
            try
            {
                //Check valid file upload
                if (nuImageUrl.HasFile && nuImageUrl.ContentLength > 0)
                {

                    string fileExtension = Path.GetExtension(nuImageUrl.FileName);
                    Double fileSize = nuImageUrl.ContentLength / 1024;

                    //Kiem tra ten mo rong file upload
                    if (!Utilities.IsValidFileExtension(fileExtension, "AllowedImageFileExtensions"))
                    {
                        lblImageUrlError.Text = ArticleResources.ImageUrlErrorFileExtension;
                        return false;
                    }
                    //Kiem tra kich thuoc file upload
                    if (!Utilities.IsValidFileSize(fileSize, "AllowedImageSize"))
                    {
                        lblImageUrlError.Text = ArticleResources.ImageUrlErrorFileSize + ConfigurationManager.AppSettings["AllowedImageSize"] + @" KB";
                        return false;
                    }
                    string path = Server.MapPath("~/" + ConfigurationManager.AppSettings["ArticleImagesFolder"]);
                    string guid = Guid.NewGuid().ToString().Replace("-", "").ToUpper();
                    System.Drawing.Image image = System.Drawing.Image.FromStream(nuImageUrl.FileContent);
                    nuImageUrl.FileContent.Close();
                    int resizeWidth;
                    int.TryParse(ConfigurationManager.AppSettings["ArticleImageMaxWidth"], out resizeWidth);
                    int resizeHeight;
                    int.TryParse(ConfigurationManager.AppSettings["ArticleImageMaxHeight"], out resizeHeight);
                    int thumbnailWidth;
                    int.TryParse(ConfigurationManager.AppSettings["ArticleImageMaxThumbnailWidth"], out thumbnailWidth);
                    int thumbnailHeight;
                    int.TryParse(ConfigurationManager.AppSettings["ArticleImageMaxThumbnailHeight"], out thumbnailHeight);
                    Utilities.ResizeImage(ref width, ref height, resizeWidth, resizeHeight, image.Width, image.Height);
                    fileName = path + guid + "_t" + fileExtension;
                    if (height != 0)
                    {
                        using (Bitmap bitmap = new Bitmap(image, width, height))
                        {
                            bitmap.Save(fileName, image.RawFormat);
                        }
                    }
                    else
                    {
                        using (Bitmap bitmap = new Bitmap(image, image.Width, image.Height))
                        {
                            bitmap.Save(fileName, image.RawFormat);
                        }
                        //nuImageUrl.MoveTo(fileName, MoveToOptions.Overwrite);
                        //fuImageUrl.PostedFile.SaveAs(fileName);
                    }
                    Utilities.ResizeImage(ref width, ref height, thumbnailWidth, thumbnailHeight, image.Width, image.Height);
                    fileName = path + guid + fileExtension;
                    if (height != 0)
                    {
                        using (Bitmap bitmap = new Bitmap(image, width, height))
                        {
                            bitmap.Save(fileName, image.RawFormat);
                        }
                    }
                    else
                    {
                        using (Bitmap bitmap = new Bitmap(image, image.Width, image.Height))
                        {
                            bitmap.Save(fileName, image.RawFormat);
                        }
                        //nuImageUrl.MoveTo(fileName, MoveToOptions.Overwrite);
                        //fuImageUrl.PostedFile.SaveAs(fileName);
                    }
                    fileName = guid + fileExtension;
                    if (!article.ImageUrl.Equals(string.Empty))
                    {
                        DeleteImageFromServer();
                    }
                    flag = true;
                }
                else
                {
                    flag = true;
                }
            }
            catch (Exception e)
            {
                lblImageUrlError.Visible = true;
                lblImageUrlError.Text = e.Message;//"Error when upload image";
            }
            return flag;
        }

        private void DeleteImageFromServer()
        {
            string thumbnailImageURL = Request.PhysicalApplicationPath + ConfigurationManager.AppSettings["ArticleImagesFolder"] + article.ImageUrl;
            thumbnailImageURL = thumbnailImageURL.Replace("/", "\\");
            string imageURL = thumbnailImageURL.Substring(0, thumbnailImageURL.LastIndexOf(".")) + "_t" + thumbnailImageURL.Substring(thumbnailImageURL.LastIndexOf("."));
            if (File.Exists(imageURL))
            {
                File.Delete(imageURL);
            }
            if (File.Exists(thumbnailImageURL))
            {
                File.Delete(thumbnailImageURL);
            }
        }

        void blog_ContentChanged(object sender, ContentChangedEventArgs e)
        {
            IndexBuilderProvider indexBuilder = IndexBuilderManager.Providers["ArticleIndexBuilderProvider"];
            if (indexBuilder != null)
            {
                indexBuilder.ContentChangedHandler(sender, e);
            }
        }

        #region Meta Data

        private void BindMeta()
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            List<ContentMeta> meta = metaRepository.FetchByContent(article.BlogGuid);
            grdContentMeta.DataSource = meta;
            grdContentMeta.DataBind();

            btnAddMeta.Visible = true;
        }

        void grdContentMeta_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            string sGuid = e.CommandArgument.ToString();
            if (sGuid.Length != 36) { return; }

            Guid guid = new Guid(sGuid);
            ContentMeta meta = metaRepository.Fetch(guid);
            if (meta == null) { return; }

            switch (e.CommandName)
            {
                case "MoveUp":
                    meta.SortRank -= 3;
                    break;

                case "MoveDown":
                    meta.SortRank += 3;
                    break;
            }

            metaRepository.Save(meta);
            List<ContentMeta> metaList = metaRepository.FetchByContent(article.BlogGuid);
            metaRepository.ResortMeta(metaList);

            article.CompiledMeta = metaRepository.GetMetaString(article.BlogGuid);
            article.Save();

            BindMeta();
            upMeta.Update();


        }

        void grdContentMeta_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            GridView grid = (GridView)sender;
// ReSharper disable PossibleNullReferenceException
            Guid guid = new Guid(grid.DataKeys[e.RowIndex].Value.ToString());
// ReSharper restore PossibleNullReferenceException
            metaRepository.Delete(guid);

            article.CompiledMeta = metaRepository.GetMetaString(article.BlogGuid);
            article.Save();
            grdContentMeta.Columns[2].Visible = true;
            BindMeta();
            upMeta.Update();
        }

        void grdContentMeta_RowEditing(object sender, GridViewEditEventArgs e)
        {
            GridView grid = (GridView)sender;
            grid.EditIndex = e.NewEditIndex;

            BindMeta();

            Button btnDeleteMeta = (Button)grid.Rows[e.NewEditIndex].Cells[1].FindControl("btnDeleteMeta");
            if (btnDeleteMeta != null)
            {
                btnDelete.Attributes.Add("OnClick", "return confirm('"
                    + ArticleResources.ContentMetaDeleteWarning + "');");
            }

            upMeta.Update();
        }

        void grdContentMeta_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            GridView grid = (GridView)sender;
            if (grid.EditIndex > -1)
            {
                if (e.Row.RowType == DataControlRowType.DataRow)
                {
                    DropDownList ddDirection = (DropDownList)e.Row.Cells[1].FindControl("ddDirection");
                    if (ddDirection != null)
                    {
                        if (e.Row.DataItem is ContentMeta)
                        {
                            ListItem item = ddDirection.Items.FindByValue(((ContentMeta)e.Row.DataItem).Dir);
                            if (item != null)
                            {
                                ddDirection.ClearSelection();
                                item.Selected = true;
                            }
                        }
                    }

                    if (!(e.Row.DataItem is ContentMeta))
                    {
                        //the add button was clicked so hide the delete button
                        Button btnDeleteMeta = (Button)e.Row.Cells[1].FindControl("btnDeleteMeta");
                        if (btnDeleteMeta != null) { btnDeleteMeta.Visible = false; }
                    }
                }
            }
        }

        void grdContentMeta_RowUpdating(object sender, GridViewUpdateEventArgs e)
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            GridView grid = (GridView)sender;

// ReSharper disable PossibleNullReferenceException
            Guid guid = new Guid(grid.DataKeys[e.RowIndex].Value.ToString());
// ReSharper restore PossibleNullReferenceException
            TextBox txtName = (TextBox)grid.Rows[e.RowIndex].Cells[1].FindControl("txtName");
            TextBox txtScheme = (TextBox)grid.Rows[e.RowIndex].Cells[1].FindControl("txtScheme");
            TextBox txtLangCode = (TextBox)grid.Rows[e.RowIndex].Cells[1].FindControl("txtLangCode");
            DropDownList ddDirection = (DropDownList)grid.Rows[e.RowIndex].Cells[1].FindControl("ddDirection");
            TextBox txtMetaContent = (TextBox)grid.Rows[e.RowIndex].Cells[1].FindControl("txtMetaContent");
            SiteUser currentSiteUser = SiteUtils.GetCurrentSiteUser();
            ContentMeta meta;
            if (guid != Guid.Empty)
            {
                meta = metaRepository.Fetch(guid);
            }
            else
            {
                meta = new ContentMeta();
                Module module = new Module(moduleId);
                meta.ModuleGuid = module.ModuleGuid;
                if (currentSiteUser != null) { meta.CreatedBy = currentSiteUser.UserGuid; }
                meta.SortRank = metaRepository.GetNextSortRank(article.BlogGuid);
            }

            if (meta != null)
            {
                meta.SiteGuid = siteSettings.SiteGuid;
                meta.ContentGuid = article.BlogGuid;
                meta.Dir = ddDirection.SelectedValue;
                meta.LangCode = txtLangCode.Text;
                meta.MetaContent = txtMetaContent.Text;
                meta.Name = txtName.Text;
                meta.Scheme = txtScheme.Text;
                if (currentSiteUser != null) { meta.LastModBy = currentSiteUser.UserGuid; }
                metaRepository.Save(meta);

                article.CompiledMeta = metaRepository.GetMetaString(article.BlogGuid);
                article.Save();

            }

            grid.EditIndex = -1;
            grdContentMeta.Columns[2].Visible = true;
            BindMeta();
            upMeta.Update();

        }

        void grdContentMeta_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
        {
            grdContentMeta.EditIndex = -1;
            grdContentMeta.Columns[2].Visible = true;
            BindMeta();
            upMeta.Update();
        }

        void btnAddMeta_Click(object sender, EventArgs e)
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add("Guid", typeof(Guid));
            dataTable.Columns.Add("SiteGuid", typeof(Guid));
            dataTable.Columns.Add("ModuleGuid", typeof(Guid));
            dataTable.Columns.Add("ContentGuid", typeof(Guid));
            dataTable.Columns.Add("Name", typeof(string));
            dataTable.Columns.Add("Scheme", typeof(string));
            dataTable.Columns.Add("LangCode", typeof(string));
            dataTable.Columns.Add("Dir", typeof(string));
            dataTable.Columns.Add("MetaContent", typeof(string));
            dataTable.Columns.Add("SortRank", typeof(int));

            DataRow row = dataTable.NewRow();
            row["Guid"] = Guid.Empty;
            row["SiteGuid"] = siteSettings.SiteGuid;
            row["ModuleGuid"] = Guid.Empty;
            row["ContentGuid"] = Guid.Empty;
            row["Name"] = string.Empty;
            row["Scheme"] = string.Empty;
            row["LangCode"] = string.Empty;
            row["Dir"] = string.Empty;
            row["MetaContent"] = string.Empty;
            row["SortRank"] = 3;

            dataTable.Rows.Add(row);

            grdContentMeta.EditIndex = 0;
            grdContentMeta.DataSource = dataTable.DefaultView;
            grdContentMeta.DataBind();
            grdContentMeta.Columns[2].Visible = false;
            btnAddMeta.Visible = false;

            upMeta.Update();

        }

        private void BindMetaLinks()
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            List<ContentMetaLink> meta = metaRepository.FetchLinksByContent(article.BlogGuid);

            grdMetaLinks.DataSource = meta;
            grdMetaLinks.DataBind();

            btnAddMetaLink.Visible = true;
        }

        void btnAddMetaLink_Click(object sender, EventArgs e)
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add("Guid", typeof(Guid));
            dataTable.Columns.Add("SiteGuid", typeof(Guid));
            dataTable.Columns.Add("ModuleGuid", typeof(Guid));
            dataTable.Columns.Add("ContentGuid", typeof(Guid));
            dataTable.Columns.Add("Rel", typeof(string));
            dataTable.Columns.Add("Href", typeof(string));
            dataTable.Columns.Add("HrefLang", typeof(string));
            dataTable.Columns.Add("SortRank", typeof(int));

            DataRow row = dataTable.NewRow();
            row["Guid"] = Guid.Empty;
            row["SiteGuid"] = siteSettings.SiteGuid;
            row["ModuleGuid"] = Guid.Empty;
            row["ContentGuid"] = Guid.Empty;
            row["Rel"] = string.Empty;
            row["Href"] = string.Empty;
            row["HrefLang"] = string.Empty;
            row["SortRank"] = 3;

            dataTable.Rows.Add(row);

            grdMetaLinks.Columns[2].Visible = false;
            grdMetaLinks.EditIndex = 0;
            grdMetaLinks.DataSource = dataTable.DefaultView;
            grdMetaLinks.DataBind();
            btnAddMetaLink.Visible = false;

            updMetaLinks.Update();
        }

        void grdMetaLinks_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            GridView grid = (GridView)sender;
            if (grid.EditIndex > -1)
            {
                if (e.Row.RowType == DataControlRowType.DataRow)
                {
                    if (!(e.Row.DataItem is ContentMetaLink))
                    {
                        //the add button was clicked so hide the delete button
                        Button btnDeleteMetaLink = (Button)e.Row.Cells[1].FindControl("btnDeleteMetaLink");
                        if (btnDeleteMetaLink != null) { btnDeleteMetaLink.Visible = false; }

                    }

                }

            }
        }

        void grdMetaLinks_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            GridView grid = (GridView)sender;
// ReSharper disable PossibleNullReferenceException
            Guid guid = new Guid(grid.DataKeys[e.RowIndex].Value.ToString());
// ReSharper restore PossibleNullReferenceException
            metaRepository.DeleteLink(guid);

            article.CompiledMeta = metaRepository.GetMetaString(article.BlogGuid);
            article.Save();

            grid.Columns[2].Visible = true;
            BindMetaLinks();

            updMetaLinks.Update();
        }

        void grdMetaLinks_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
        {
            grdMetaLinks.EditIndex = -1;
            grdMetaLinks.Columns[2].Visible = true;
            BindMetaLinks();
            updMetaLinks.Update();
        }

        void grdMetaLinks_RowUpdating(object sender, GridViewUpdateEventArgs e)
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            GridView grid = (GridView)sender;

// ReSharper disable PossibleNullReferenceException
            Guid guid = new Guid(grid.DataKeys[e.RowIndex].Value.ToString());
// ReSharper restore PossibleNullReferenceException
            TextBox txtRel = (TextBox)grid.Rows[e.RowIndex].Cells[1].FindControl("txtRel");
            TextBox txtHref = (TextBox)grid.Rows[e.RowIndex].Cells[1].FindControl("txtHref");
            TextBox txtHrefLang = (TextBox)grid.Rows[e.RowIndex].Cells[1].FindControl("txtHrefLang");
            SiteUser currentUser = SiteUtils.GetCurrentSiteUser();
            ContentMetaLink meta;
            if (guid != Guid.Empty)
            {
                meta = metaRepository.FetchLink(guid);
            }
            else
            {
                meta = new ContentMetaLink();
                Module module = new Module(moduleId);
                meta.ModuleGuid = module.ModuleGuid;
                if (currentUser != null) { meta.CreatedBy = currentUser.UserGuid; }
                meta.SortRank = metaRepository.GetNextLinkSortRank(article.BlogGuid);
            }

            if (meta != null)
            {
                meta.SiteGuid = siteSettings.SiteGuid;
                meta.ContentGuid = article.BlogGuid;
                meta.Rel = txtRel.Text;
                meta.Href = txtHref.Text;
                meta.HrefLang = txtHrefLang.Text;

                if (currentUser != null) { meta.LastModBy = currentUser.UserGuid; }
                metaRepository.Save(meta);

                article.CompiledMeta = metaRepository.GetMetaString(article.BlogGuid);
                article.Save();

            }

            grid.EditIndex = -1;
            grdMetaLinks.Columns[2].Visible = true;
            BindMetaLinks();
            updMetaLinks.Update();
        }

        void grdMetaLinks_RowEditing(object sender, GridViewEditEventArgs e)
        {
            GridView grid = (GridView)sender;
            grid.EditIndex = e.NewEditIndex;

            BindMetaLinks();

// ReSharper disable PossibleNullReferenceException
            Guid guid = new Guid(grid.DataKeys[grid.EditIndex].Value.ToString());
// ReSharper restore PossibleNullReferenceException

            Button btnDeleteMetaLink = (Button)grid.Rows[e.NewEditIndex].Cells[1].FindControl("btnDeleteMetaLink");
            if (btnDeleteMetaLink != null)
            {
                btnDeleteMetaLink.Attributes.Add("OnClick", "return confirm('"
                    + ArticleResources.ContentMetaLinkDeleteWarning + "');");

                if (guid == Guid.Empty) { btnDeleteMetaLink.Visible = false; }
            }

            updMetaLinks.Update();
        }

        void grdMetaLinks_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (article == null) { return; }
            if (article.BlogGuid == Guid.Empty) { return; }

            string sGuid = e.CommandArgument.ToString();
            if (sGuid.Length != 36) { return; }

            Guid guid = new Guid(sGuid);
            ContentMetaLink meta = metaRepository.FetchLink(guid);
            if (meta == null) { return; }

            switch (e.CommandName)
            {
                case "MoveUp":
                    meta.SortRank -= 3;
                    break;

                case "MoveDown":
                    meta.SortRank += 3;
                    break;

            }

            metaRepository.Save(meta);
            List<ContentMetaLink> metaList = metaRepository.FetchLinksByContent(article.BlogGuid);
            metaRepository.ResortMeta(metaList);

            article.CompiledMeta = metaRepository.GetMetaString(article.BlogGuid);
            article.Save();

            BindMetaLinks();
            updMetaLinks.Update();
        }


        #endregion

        #region History

        private void BindHistory()
        {
            if (!enableContentVersioning) { return; }

            if ((article == null) || (article.ItemId == -1))
            {
                pnlHistory.Visible = false;
                return;
            }

            List<ContentHistory> history = ContentHistory.GetPage(article.BlogGuid, pageNumber, pageSize, out totalPages);

            pgrHistory.ShowFirstLast = true;
            pgrHistory.PageSize = pageSize;
            pgrHistory.PageCount = totalPages;
            pgrHistory.Visible = (totalPages > 1);

            grdHistory.DataSource = history;
            grdHistory.DataBind();

            btnDeleteHistory.Visible = (grdHistory.Rows.Count > 0);
            pnlHistory.Visible = (grdHistory.Rows.Count > 0);

        }

        void pgrHistory_Command(object sender, CommandEventArgs e)
        {
            pageNumber = Convert.ToInt32(e.CommandArgument);
            pgrHistory.CurrentIndex = pageNumber;
            BindHistory();
        }

        void grdHistory_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            string g = e.CommandArgument.ToString();
            if (g.Length != 36) { return; }
            Guid historyGuid = new Guid(g);

            switch (e.CommandName)
            {
                case "RestoreToEditor":
                    ContentHistory history = new ContentHistory(historyGuid);
                    if (history.Guid == Guid.Empty) { return; }

                    edContent.Text = history.ContentText;
                    BindHistory();
                    break;

                case "DeleteHistory":
                    ContentHistory.Delete(historyGuid);
                    BindHistory();
                    break;

                default:

                    break;
            }
        }

        void grdHistory_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            Button button = (Button)e.Row.Cells[0].FindControl("btnDelete");
            if (button != null)
            {
                button.Attributes.Add("OnClick", "return confirm('"
                    + ArticleResources.DeleteHistoryItemWarning + "');");
            }
        }

        void btnRestoreFromGreyBox_Click(object sender, ImageClickEventArgs e)
        {
            if (hdnHxToRestore.Value.Length != 36)
            {
                BindHistory();
                return;
            }

            Guid h = new Guid(hdnHxToRestore.Value);

            ContentHistory history = new ContentHistory(h);
            if (history.Guid == Guid.Empty) { return; }

            edContent.Text = history.ContentText;
            BindHistory();

        }

        void btnDeleteHistory_Click(object sender, EventArgs e)
        {
            if (article == null) { return; }

            ContentHistory.DeleteByContent(article.BlogGuid);
            BindHistory();

        }

        #endregion

        private void DoPings(object pingersList)
        {

            if (!(pingersList is List<ServicePinger>)) return;

            List<ServicePinger> pingers = pingersList as List<ServicePinger>;
            foreach (ServicePinger pinger in pingers)
            {
                pinger.Ping();
            }

        }

        protected virtual void QueuePings()
        {
            if (config.OdiogoFeedId.Length == 0) return;

            const string odogioRpcUrl = "http://rpc.odiogo.com/ping/";
            ServicePinger pinger = new ServicePinger(
                siteSettings.SiteName,
                SiteRoot,
                odogioRpcUrl);

            List<ServicePinger> pingers = new List<ServicePinger> {pinger};


            if (!ThreadPool.QueueUserWorkItem(DoPings, pingers))
            {
                throw new Exception("Couldn't queue the DoPings on a new thread.");
            }


        }



        protected void btnCancel_Click(object sender, EventArgs e)
        {
            if (hdnReturnUrl.Value.Length > 0)
            {
                WebUtils.SetupRedirect(this, hdnReturnUrl.Value);
                return;
            }

            WebUtils.SetupRedirect(this, SiteUtils.GetCurrentPageUrl());

            return;

        }

        protected void btnDelete_Click(object sender, EventArgs e)
        {
            if (article != null)
            {
                if (!article.ImageUrl.Equals(string.Empty))
                {
                    DeleteImageFromServer();
                }
                DeleteAttachments();
                article.ContentChanged += blog_ContentChanged;
                article.Delete();
                if (articleSync != null)
                {
                    articleSync.ContentChanged += blog_ContentChanged;
                    articleSync.Delete();
                    FriendlyUrl.DeleteByPageGuid(articleSync.BlogGuid);
                }
                FriendlyUrl.DeleteByPageGuid(article.BlogGuid);
                CurrentPage.UpdateLastModifiedTime();
                SiteUtils.QueueIndexing();
            }

            //if (hdnReturnUrl.Value.Length > 0)
            //{
            //    WebUtils.SetupRedirect(this, hdnReturnUrl.Value);
            //    return;
            //}

            WebUtils.SetupRedirect(this, SiteUtils.GetCurrentPageUrl());

            return;
        }

        private void DeleteAttachments()
        {
            for (int i = 0; i < rptAttachments.Items.Count; i++)
            {
                ImageButton ibtnDelete = (ImageButton) rptAttachments.Items[i].FindControl("ibtnDelete");
                DBArticleAttachment repository = new DBArticleAttachment();
                bool a = repository.DeleteItemAttachment(ibtnDelete.CommandArgument);
                bool b = repository.Delete(ibtnDelete.CommandArgument);
                if (!a || !b) continue;
                string path = Request.PhysicalApplicationPath + "Data/ArticleAttachments/" +
                              ibtnDelete.CommandArgument;
                path = path.Replace("/", "\\");
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
            }
        }



        private void PopulateCommentDaysDropdown()
        {
            ListItem item = ddCommentAllowedForDays.Items.FindByValue(config.DefaultCommentDaysAllowed.ToInvariantString());
            if (item == null) return;
            ddCommentAllowedForDays.ClearSelection();
            item.Selected = true;
        }

        private void PopulateLabels()
        {
            Title = SiteUtils.FormatPageTitle(siteSettings, ArticleResources.EditPostPageTitle);
            moduleTitle.Header = ArticleResources.BlogEditEntryLabel;

            pnlOverrideUrl.Visible = config.UseOverrideUrl;

            progressBar.AddTrigger(btnUpload);
            progressBar.AddTrigger(btnUpdate);

            litContentTab.Text = @"<a href='#tabContent'>" + ArticleResources.ContentTab + @"</a>";
            litExcerptTab.Text = @"<a href='#" + tabExcerpt.ClientID + @"'>" + ArticleResources.ExcerptTab + @"</a>";
            litSyncPost.Text = @"<a href='#" + tabSyncPost.ClientID + @"'>" + ArticleResources.SyncPostTab + @"</a>";
            litMetaTab.Text = @"<a href='#tabMeta'>" + ArticleResources.MetaTab + @"</a>";

            liExcerpt.Visible = config.UseExcerpt || config.UseExcerptInFeed;
            tabExcerpt.Visible = config.UseExcerpt || config.UseExcerptInFeed;

            liSyncPost.Visible = loadedModuleId > -1;
            tabSyncPost.Visible = loadedModuleId > -1;

            pnlComments.Visible = config.AllowComments;

            if (isUserPost && !isPublisher)
            {
                chkIsPublished.Checked = false;
                pnlIsPublished.Visible = false;
            }

            if (UserCanEditModule(moduleId) || isPublisher)
            {
                chkIsPublished.Checked = true;
                pnlIsPublished.Visible = true;
            }

            if (!Page.IsPostBack)
            {
                PopulateCommentDaysDropdown();
            }

            pnlPublishSyncPost.Visible = config.SyncPostPublished;

            btnDeleteImg.ImageUrl = "~/Data/SiteImages/delete.gif";
            btnDeleteImg.ToolTip = ArticleResources.ArticleDeleteLinkText;

            edContent.WebEditor.ToolBar = ToolBar.FullWithTemplates;
            edExcerpt.WebEditor.ToolBar = ToolBar.FullWithTemplates;

            lnkEditCategories.NavigateUrl = SiteRoot + "/Article/EditCategory.aspx?pageid=" + CurrentPage.PageId.ToInvariantString()
                + "&mid=" + moduleId.ToInvariantString();

            lnkEditCategories.Text = ArticleResources.BlogEditCategoriesLabel;

            edContent.WebEditor.Height = config.EditorHeight;
            edExcerpt.WebEditor.Height = config.EditorHeight;


            btnUpdate.Text = ArticleResources.BlogEditUpdateButton;
            SiteUtils.SetButtonAccessKey(btnUpdate, ArticleResources.BlogEditUpdateButtonAccessKey);
            btnUpdate2.Text = ArticleResources.BlogEditUpdateButton;
            btnUpdate3.Text = ArticleResources.BlogEditUpdateButton;
            btnUpdate4.Text = ArticleResources.BlogEditUpdateButton;
            btnSaveAndPreview.Text = ArticleResources.SaveAndPreviewButton;

            UIHelper.DisableButtonAfterClick(
                btnUpdate,
                ArticleResources.ButtonDisabledPleaseWait,
                Page.ClientScript.GetPostBackEventReference(btnUpdate, string.Empty)
                );

            UIHelper.DisableButtonAfterClick(
                btnUpdate2,
                ArticleResources.ButtonDisabledPleaseWait,
                Page.ClientScript.GetPostBackEventReference(btnUpdate2, string.Empty)
                );

            UIHelper.DisableButtonAfterClick(
                btnUpdate3,
                ArticleResources.ButtonDisabledPleaseWait,
                Page.ClientScript.GetPostBackEventReference(btnUpdate3, string.Empty)
                );

            UIHelper.DisableButtonAfterClick(
                btnUpdate4,
                ArticleResources.ButtonDisabledPleaseWait,
                Page.ClientScript.GetPostBackEventReference(btnUpdate4, string.Empty)
                );

            UIHelper.DisableButtonAfterClick(
                btnSaveAndPreview,
                ArticleResources.ButtonDisabledPleaseWait,
                Page.ClientScript.GetPostBackEventReference(btnSaveAndPreview, string.Empty)
                );

            lnkCancel.Text = ArticleResources.BlogEditCancelButton;
            lnkCancel2.Text = ArticleResources.BlogEditCancelButton;
            lnkCancel3.Text = ArticleResources.BlogEditCancelButton;
            lnkCancel4.Text = ArticleResources.BlogEditCancelButton;
            btnDelete.Text = ArticleResources.BlogEditDeleteButton;
            btnDelete2.Text = ArticleResources.BlogEditDeleteButton;
            btnDelete3.Text = ArticleResources.BlogEditDeleteButton;
            btnDelete4.Text = ArticleResources.BlogEditDeleteButton;
            SiteUtils.SetButtonAccessKey(btnDelete, ArticleResources.BlogEditDeleteButtonAccessKey);
            UIHelper.AddConfirmationDialog(btnDelete, ArticleResources.BlogDeletePostWarning);
            UIHelper.AddConfirmationDialog(btnDelete2, ArticleResources.BlogDeletePostWarning);
            UIHelper.AddConfirmationDialog(btnDelete3, ArticleResources.BlogDeletePostWarning);
            UIHelper.AddConfirmationDialog(btnDelete4, ArticleResources.BlogDeletePostWarning);

            reqTitle.ErrorMessage = ArticleResources.TitleRequiredWarning;
            reqStartDate.ErrorMessage = ArticleResources.BlogBeginDateRequiredHelp;
            dpBeginDate.ClockHours = ConfigurationManager.AppSettings["ClockHours"];
            regexUrl.ErrorMessage = ArticleResources.FriendlyUrlRegexWarning;

            //if (!showCategories)
            //{
            //    pnlCategories.Visible = false;
            //}

            litDays.Text = ArticleResources.BlogEditCommentsDaysLabel;

            grdHistory.Columns[0].HeaderText = ArticleResources.CreatedDateGridHeader;
            grdHistory.Columns[1].HeaderText = ArticleResources.ArchiveDateGridHeader;

            btnRestoreFromGreyBox.ImageUrl = Page.ResolveUrl("~/Data/SiteImages/1x1.gif");
            btnRestoreFromGreyBox.AlternateText = @" ";

            btnDeleteHistory.Text = ArticleResources.DeleteAllHistoryButton;
            UIHelper.AddConfirmationDialog(btnDeleteHistory, ArticleResources.DeleteAllHistoryWarning);

            btnAddMeta.Text = ArticleResources.AddMetaButton;
            grdContentMeta.Columns[0].HeaderText = string.Empty;
            grdContentMeta.Columns[1].HeaderText = ArticleResources.ContentMetaNameLabel;
            grdContentMeta.Columns[2].HeaderText = ArticleResources.ContentMetaMetaContentLabel;

            btnAddMetaLink.Text = ArticleResources.AddMetaLinkButton;

            grdMetaLinks.Columns[0].HeaderText = string.Empty;
            grdMetaLinks.Columns[1].HeaderText = ArticleResources.ContentMetaRelLabel;
            grdMetaLinks.Columns[2].HeaderText = ArticleResources.ContentMetaMetaHrefLabel;

            lblImageUrlError.Text = ArticleResources.ImageUrlErrorLabel + ConfigurationManager.AppSettings["AllowedImageFileExtensions"]
                + @" -- " + ArticleResources.ImageUrlErrorLabelFileSize + ConfigurationManager.AppSettings["AllowedImageSize"] + @" KB";

        }

        private void LoadSettings()
        {
            if ((WebUser.IsAdminOrContentAdmin) || (SiteUtils.UserIsSiteEditor())) { isAdmin = true; }
            
            Hashtable getModuleSettings = ModuleSettings.GetModuleSettings(moduleId);
            config = new ArticleConfiguration(getModuleSettings);
            
            if (WebUser.IsInRoles(config.RolePost) || WebUser.IsInRoles(config.RolePublished))
            {
                isUserPost = true;
            }

            if (WebUser.IsInRoles(config.RolePublished))
            {
                isPublisher = true;
            }

            lnkCancel.NavigateUrl = SiteUtils.GetCurrentPageUrl();

            enableContentVersioning = config.EnableContentVersioning;

            if ((siteSettings.ForceContentVersioning) || (WebConfigSettings.EnforceContentVersioningGlobally))
            {
                enableContentVersioning = true;
            }

            if (itemId > -1)
            {
                article = new Article(itemId);
                if (article.ModuleId != moduleId) { article = null; }
                itemCategory = repositoryCategory.GetOneByArticleID(itemId);
                if(catId == -1 && itemCategory != null)
                {
                    catId = itemCategory.CategoryID;
                }
                if (article != null && article.SyncItemID > 0)
                {
                    articleSync = new Article(article.SyncItemID);
                }
            }
            pnlAttachment.Visible = config.UseAttachmentSetting;

            pnlMetaData.Visible = (article != null);

            if (!config.ArticleCategoriesSelected.Equals(string.Empty))
            {
                string loadedCategory = config.ArticleCategoriesSelected;
                if (!loadedCategory.Equals(string.Empty))
                {
                    int.TryParse(loadedCategory.Remove(loadedCategory.IndexOf("-")), out loadedModuleId);
                    int.TryParse(loadedCategory.Remove(0, loadedCategory.IndexOf("-") + 1), out loadedPageId);
                    Module m = new Module(loadedModuleId);
                    loadedSiteId = m.SiteId;
                    settingsSync = new SiteSettings(loadedSiteId);
                }
            }
            else
            {
                loadedModuleId = -1;
                loadedPageId = -1;
                loadedSiteId = -1;
                settingsSync = new SiteSettings();
            }

            divHistoryDelete.Visible = (enableContentVersioning && isAdmin);

            pnlHistory.Visible = enableContentVersioning;

            if (enableContentVersioning)
            {
                SetupHistoryRestoreScript();
            }

            try
            {
                // this keeps the action from changing during ajax postback in folder based sites
                SiteUtils.SetFormAction(Page, Request.RawUrl);
            }
            catch (MissingMethodException)
            {
                //this method was introduced in .NET 3.5 SP1
            }
        }

        private void SetupHistoryRestoreScript()
        {
            StringBuilder script = new StringBuilder();

            script.Append("\n<script type='text/javascript'>");
            script.Append("function LoadHistoryInEditor(hxGuid) {");

            script.Append("GB_hide();");
            //script.Append("alert(hxGuid);");

            script.Append("var hdn = document.getElementById('" + hdnHxToRestore.ClientID + "'); ");
            script.Append("hdn.value = hxGuid; ");
            script.Append("var btn = document.getElementById('" + btnRestoreFromGreyBox.ClientID + "');  ");
            script.Append("btn.click(); ");
            script.Append("}");
            script.Append("</script>");


            Page.ClientScript.RegisterStartupScript(typeof(Page), "gbHandler", script.ToString());

        }

        private void LoadParams()
        {
            timeOffset = SiteUtils.GetUserTimeOffset();
            timeZone = SiteUtils.GetUserTimeZone();
            pageId = WebUtils.ParseInt32FromQueryString("pageid", -1);
            moduleId = WebUtils.ParseInt32FromQueryString("mid", -1);
            itemId = WebUtils.ParseInt32FromQueryString("ItemID", -1);
            catId = WebUtils.ParseInt32FromQueryString("catid", -1);
            restoreGuid = WebUtils.ParseGuidFromQueryString("r", restoreGuid);
            cacheDependencyKey = "Module-" + moduleId.ToInvariantString();
            virtualRoot = WebUtils.GetApplicationRoot();


        }

        private void LoadPanels()
        {
            bool showLeftColumnAdmin = ConfigHelper.GetBoolProperty("ShowLeftColumnAdmin", false);
            bool showRightColumnAdmin = ConfigHelper.GetBoolProperty("ShowRightColumnAdmin", false);
            bool showTopColumnAdmin = ConfigHelper.GetBoolProperty("ShowTopColumnAdmin", false);
            bool showBottomColumnAdmin = ConfigHelper.GetBoolProperty("ShowBottomColumnAdmin", false);
            int showCenterColumnAdmin = ConfigHelper.GetIntProperty("ShowCenterColumnAdmin", 0);
            LoadSideContent(showLeftColumnAdmin, showRightColumnAdmin, showTopColumnAdmin, showBottomColumnAdmin, showCenterColumnAdmin);
        }

        private void SetupScripts()
        {
            if (!Page.ClientScript.IsClientScriptBlockRegistered("sarissa"))
            {
                Page.ClientScript.RegisterClientScriptBlock(GetType(), "sarissa", "<script src=\""
                    + ResolveUrl("~/ClientScript/sarissa/sarissa.js") + "\" type=\"text/javascript\"></script>");
            }

            if (!Page.ClientScript.IsClientScriptBlockRegistered("sarissa_ieemu_xpath"))
            {
                Page.ClientScript.RegisterClientScriptBlock(GetType(), "sarissa_ieemu_xpath", "<script src=\""
                    + ResolveUrl("~/ClientScript/sarissa/sarissa_ieemu_xpath.js") + "\" type=\"text/javascript\"></script>");
            }


            if (!Page.ClientScript.IsClientScriptBlockRegistered("friendlyurlsuggest"))
            {
                Page.ClientScript.RegisterClientScriptBlock(GetType(), "friendlyurlsuggest", "<script src=\""
                    + ResolveUrl("~/ClientScript/friendlyurlsuggest_v2.js") + "\" type=\"text/javascript\"></script>");
            }

            string focusScript = string.Empty;
            if (itemId == -1) { focusScript = "document.getElementById('" + txtTitle.ClientID + "').focus();"; }

            string hookupInputScript = "<script type=\"text/javascript\">"
                + "new UrlHelper( "
                + "document.getElementById('" + txtTitle.ClientID + "'),  "
                + "document.getElementById('" + txtItemUrl.ClientID + "'), "
                + "document.getElementById('" + hdnTitle.ClientID + "'), "
                + "document.getElementById('" + spnUrlWarning.ClientID + "'), "
                + "\"" + SiteRoot + "/Article/BlogUrlSuggestService.ashx" + "\""
                + "); " + focusScript + "</script>";

            if (!Page.ClientScript.IsStartupScriptRegistered(UniqueID + "urlscript"))
            {
                Page.ClientScript.RegisterStartupScript(
                    GetType(),
                    UniqueID + "urlscript", hookupInputScript);
            }


        }

    }
}
